package com.sh.rbac.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.rbac.core.common.constant.CacheConstants;
import com.sh.rbac.core.common.util.WebUtils;
import com.sh.rbac.core.security.util.SecurityHolderUtils;
import com.sh.rbac.domain.converter.RoleConverter;
import com.sh.rbac.domain.dto.role.RoleAuthDTO;
import com.sh.rbac.domain.dto.role.RoleQueryDTO;
import com.sh.rbac.domain.dto.role.RoleSaveDTO;
import com.sh.rbac.domain.dto.role.RoleUpdateDTO;
import com.sh.rbac.domain.entity.Role;
import com.sh.rbac.domain.entity.RoleMenu;
import com.sh.rbac.domain.entity.User;
import com.sh.rbac.mapper.RoleMapper;
import com.sh.rbac.mapper.RoleMenuMapper;
import com.sh.rbac.service.MenuService;
import com.sh.rbac.service.OnlineUserService;
import com.sh.rbac.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.List;

/**
 * @author lucky
 * @description 针对表【sys_role(角色表)】的数据库操作Service实现
 * @createDate 2024-04-04 21:47:19
 */

@Slf4j
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role>
        implements RoleService {

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private MenuService menuService;
    @Autowired
    private OnlineUserService onlineUserService;


    @Override
    public Role getById(Serializable id) {
        Role role = super.getById(id);

        List<Long> menuIds = roleMenuMapper.selectObjs(
                new LambdaQueryWrapper<RoleMenu>()
                        .eq(RoleMenu::getRoleId, id)
                        .select(RoleMenu::getMenuId)
        );
        role.setMenuIds(menuIds);

        return role;
    }

    @Override
    public Page<Role> getPage(Long current, Long limit, RoleQueryDTO roleQueryDTO) {
        // 创建 page 对象，传递当前页, 每页记录数
        Page<Role> page = new Page<>(current, limit);

        // 条件参数
        String name = roleQueryDTO.getName();
        String roleKey = roleQueryDTO.getRoleKey();
        Integer dataScope = roleQueryDTO.getDataScope();
        Integer status = roleQueryDTO.getStatus();

        // 构建条件
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(name), Role::getName, name)
                .like(StrUtil.isNotBlank(roleKey), Role::getRoleKey, roleKey)
                .eq(dataScope != null, Role::getDataScope, dataScope)
                .eq(status != null, Role::getStatus, status);

        // 根据修改时间倒序
        queryWrapper.orderByDesc(Role::getUpdateTime);

        // 返回结果
        return baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public Boolean saveAuth(RoleAuthDTO roleAuthDTO) {
        Long roleId = roleAuthDTO.getRoleId();

        // 删除角色权限
        roleMenuMapper.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, roleId));

        // 保存角色权限
        if (!roleAuthDTO.getMenuIds().isEmpty()) {
            roleMenuMapper.insertBatch(roleAuthDTO);
        }

        // 刷新当前用户权限
        if (SecurityHolderUtils.getRoleIds().contains(roleId)) {
            // 更新当前登录用户的权限
            User loginUser = SecurityHolderUtils.getLoginUser();
            loginUser.setPermissions(menuService.getAuth());
            redisTemplate.opsForValue().set(CacheConstants.LOGIN_USER_KEY + WebUtils.getToken(), loginUser);
        }

        // 其他在线用户强制登出
        List<User> userList = onlineUserService.getAll();
        userList.forEach(u -> {
                    // 忽略当前用户
                    if (u.getToken().equals(WebUtils.getToken())) {
                        return;
                    }

                    // 强制退出包含这个角色的用户
                    u.getRoles().forEach(r -> {
                        if (r.getId().equals(roleId)) {
                            redisTemplate.delete(CacheConstants.LOGIN_USER_KEY + u.getToken());
                        }
                    });
                }
        );

        return true;
    }

    @Override
    public Boolean save(RoleSaveDTO roleSaveDTO) {
        Role role = RoleConverter.INSTANCE.toEntity(roleSaveDTO);
        return super.save(role);
    }

    @Override
    public Boolean updateById(RoleUpdateDTO roleUpdateDTO) {
        Role role = RoleConverter.INSTANCE.toEntity(roleUpdateDTO);
        return super.updateById(role);
    }

    @Override
    public Boolean updateStatus(Long id, Integer status) {
        Role role = new Role();
        role.setId(id);
        role.setStatus(status);

        return super.updateById(role);
    }
}




